using System;
using Autofac;
using Autofac.Builder;
using Autofac.Registrars;

namespace Photon.Container
{
	/// <summary>
	/// Base class for the Dsl configurations
	/// </summary>
	public abstract class ConfiguratorBase : ContainerBuilder,  IModule
	{
		/// <summary>
		/// Gets or sets the container.
		/// </summary>
		/// <value>The container.</value>
		protected IContainer Container { get; private set; }
		
		/// <summary>
		/// The method to be implemented by DSL
		/// </summary>
		protected abstract void Execute();

		/// <summary>
		/// Apply the module to the container.
		/// </summary>
		/// <param name="container">Container to apply configuration to.</param>
		public void Configure(IContainer container)
		{
			Container = container;
			
			Execute();

			Build(container);
		}

		/// <summary>
		/// Registration shortcut.
		/// </summary>
		/// <param name="type">The type.</param>
		/// <param name="service">The service.</param>
		/// <param name="name">The name.</param>
		/// <returns></returns>
		protected IReflectiveRegistrar Register(Type type, Type service, string name)
		{
			return Register(type).As(service).Named(name);
		}

		/// <summary>
		/// Registration shortcut
		/// </summary>
		/// <param name="type">The type.</param>
		/// <param name="service">The service.</param>
		/// <returns></returns>
		protected IReflectiveRegistrar Register(Type type, Type service)
		{
			return Register(type).As(service);
		}

		/// <summary>
		/// Registers the specified type.
		/// </summary>
		/// <param name="type">The type.</param>
		/// <param name="name">The name.</param>
		/// <returns></returns>
		protected IReflectiveRegistrar Register(Type type, string name)
		{
			return Register(type).Named(name);
		}

		/// <summary>
		/// Registers the specified object.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="item">The item.</param>
		/// <param name="service">The service.</param>
		/// <returns></returns>
		protected IConcreteRegistrar Register<T>(T item, Type service)
		{
			return Register(item).As(service);
		}
		

		/// <summary>
		/// Registers the module inside the builder.
		/// </summary>
		/// <typeparam name="TModule">The type of the module.</typeparam>
		/// <param name="module">The module.</param>
		/// <returns></returns>
		protected TModule Load<TModule>(TModule module) where TModule : IModule
		{
			RegisterModule(module);
			return module;
		}

		/// <summary>
		/// Loads the specified modules.
		/// </summary>
		/// <param name="modules">The modules.</param>
		protected void Load(params Type[] modules)
		{
			foreach (var type in modules)
			{
				Enforce.ThatArgument(
					typeof(IModule).IsAssignableFrom(type), 
					"modules",
					string.Format("{0} is not a module type", type));
				
				RegisterModule((IModule) Activator.CreateInstance(type));
			}
		}
	}
}